﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using XNAGuiLib.Core.Utilities;

namespace XNAGuiLib.Core.ActionHandling
{
    public class MouseAction : Action
    {

        #region MouseAction Public Field - MouseKey
        protected Enums.MouseKeys _mouseKey;
        /// <summary>
        /// gets or sets the mouse key to check for triggering this action
        /// </summary>
        public Enums.MouseKeys MouseKey
        {
            get
            {
                return _mouseKey;
            }
            set
            {
                _mouseKey = value;
            }
        }
        #endregion

        #region MouseAction Public Field - MouseKeyPosition
        protected Enums.MouseKeyPositions _mouseKeyPosition;
        /// <summary>
        /// gets or sets the mouse key position the mouse key have to be in for trigger
        /// </summary>
        public Enums.MouseKeyPositions MouseKeyPosition
        {
            get
            {
                return _mouseKeyPosition;
            }
            set
            {
                _mouseKeyPosition = value;
            }
        }
        #endregion

        #region MouseAction Public Field - KeyMod
        // optional key modifier for this mouse action to be checked for
        protected KeyModifier _keyMod = KeyModifier.ALT_L;
        /// <summary>
        /// gets or sets the KeyModifier for this MouseAction
        /// </summary>
        public KeyModifier KeyMod
        {
            get
            {
                return _keyMod;
            }
            set
            {
                _keyMod = value;
            }
        }
        #endregion


        public MouseAction(GIComponent invoker, IAction target, string command, Enums.MouseKeys mouseKey, Enums.MouseKeyPositions mouseKeyPos, KeyModifier keyModifier)
            : base(invoker, target, command)
        {
            this._mouseKey = mouseKey;
            this._mouseKeyPosition = mouseKeyPos;
            this._keyMod = keyModifier;
            invoker.Add(this);
        }


        #region Public Method - CheckMouse
        public bool CheckMouse(Enums.MouseKeys mouseKey)
        {
            switch (mouseKey)
            {
                case Enums.MouseKeys.Left:
                    return this.CheckLeftButton();

                case Enums.MouseKeys.Middle:
                    return this.CheckMiddleButton();

                case Enums.MouseKeys.Right:
                    return this.CheckRightButton();

                case Enums.MouseKeys.XButton1:
                    return this.CheckXButton1();

                case Enums.MouseKeys.XButton2:
                    return this.CheckXButton2();
            }

            return false;
        }
        #endregion


        #region Private Methods - CheckLeftButton

        #region Private Method - CheckLeftButton()
        private bool CheckLeftButton()
        {
            switch (_mouseKeyPosition)
            {
                case Enums.MouseKeyPositions.Down:
                    return CheckLeftButtonDown(_ms);

                case Enums.MouseKeyPositions.Released:
                    return CheckLeftButtonReleased(_ms);

                case Enums.MouseKeyPositions.Pressed:
                    return CheckLeftButtonPressed(_ms, _oms);
            }
            return false;
        }
        #endregion

        #region Private Method - CheckLeftButtonDown(MouseState ms)
        private bool CheckLeftButtonDown(MouseState ms)
        {
            if (ms.LeftButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckLeftButtonReleased(MouseState ms)
        private bool CheckLeftButtonReleased(MouseState ms)
        {
            if (ms.LeftButton == ButtonState.Released)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckLeftButtonPressed(MouseState ms, MouseState oms)
        private bool CheckLeftButtonPressed(MouseState ms, MouseState oms)
        {
            if (CheckLeftButtonReleased(ms) 
                && CheckLeftButtonDown(oms)
                && _invoker.Rectangle.Intersects(new Rectangle(ms.X, ms.Y, 1, 1)))
                return true;
            else
                return false;
        }
        #endregion

        #endregion

        #region Private Methods - CheckRightButton

        #region Private Method - CheckRightButton()
        private bool CheckRightButton()
        {
            switch (_mouseKeyPosition)
            {
                case Enums.MouseKeyPositions.Down:
                    return CheckRightButtonDown(_ms);

                case Enums.MouseKeyPositions.Released:
                    return CheckRightButtonReleased(_ms);

                case Enums.MouseKeyPositions.Pressed:
                    return CheckRightButtonPressed(_ms, _oms);
            }
            return false;
        }
        #endregion

        #region Private Method - CheckRightButtonDown(MouseState ms)
        private bool CheckRightButtonDown(MouseState ms)
        {
            if (ms.RightButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckRightButtonReleased(MouseState ms)
        private bool CheckRightButtonReleased(MouseState ms)
        {
            if (ms.RightButton == ButtonState.Released)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckRightButtonPressed(MouseState ms, MouseState oms)
        private bool CheckRightButtonPressed(MouseState ms, MouseState oms)
        {
            if (CheckRightButtonReleased(ms)
                && CheckRightButtonDown(oms)
                && _invoker.Rectangle.Intersects(new Rectangle(ms.X, ms.Y, 1, 1)))
                return true;
            else
                return false;
        }
        #endregion

        #endregion

        #region Private Methods - CheckMiddleButton

        #region Private Method - CheckMiddleButton()
        private bool CheckMiddleButton()
        {
            switch (_mouseKeyPosition)
            {
                case Enums.MouseKeyPositions.Down:
                    return CheckMiddleButtonDown(_ms);

                case Enums.MouseKeyPositions.Released:
                    return CheckMiddleButtonReleased(_ms);

                case Enums.MouseKeyPositions.Pressed:
                    return CheckMiddleButtonPressed(_ms, _oms);
            }
            return false;
        }
        #endregion

        #region Private Method - CheckMiddleButtonDown(MouseState ms)
        private bool CheckMiddleButtonDown(MouseState ms)
        {
            if (ms.MiddleButton == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckMiddleButtonReleased(MouseState ms)
        private bool CheckMiddleButtonReleased(MouseState ms)
        {
            if (ms.MiddleButton == ButtonState.Released)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckMiddleButtonPressed(MouseState ms, MouseState oms)
        private bool CheckMiddleButtonPressed(MouseState ms, MouseState oms)
        {
            if (CheckMiddleButtonReleased(ms)
                && CheckMiddleButtonDown(oms)
                && _invoker.Rectangle.Intersects(new Rectangle(ms.X, ms.Y, 1, 1)))
                return true;
            else
                return false;
        }
        #endregion

        #endregion

        #region Private Methods - CheckXButton1

        #region Private Method - CheckXButton1()
        private bool CheckXButton1()
        {
            switch (_mouseKeyPosition)
            {
                case Enums.MouseKeyPositions.Down:
                    return CheckXButton1Down(_ms);

                case Enums.MouseKeyPositions.Released:
                    return CheckXButton1Released(_ms);

                case Enums.MouseKeyPositions.Pressed:
                    return CheckXButton1Pressed(_ms, _oms);
            }
            return false;
        }
        #endregion

        #region Private Method - CheckXButton1Down(MouseState ms)
        private bool CheckXButton1Down(MouseState ms)
        {
            if (ms.XButton1 == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckXButton1Released(MouseState ms)
        private bool CheckXButton1Released(MouseState ms)
        {
            if (ms.XButton1 == ButtonState.Released)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckXButton1Pressed(MouseState ms, MouseState oms)
        private bool CheckXButton1Pressed(MouseState ms, MouseState oms)
        {
            if (CheckXButton1Released(ms)
                && CheckXButton1Down(oms)
                && _invoker.Rectangle.Intersects(new Rectangle(ms.X, ms.Y, 1, 1)))
                return true;
            else
                return false;
        }
        #endregion

        #endregion

        #region Private Methods - CheckXButton2

        #region Private Method - CheckXButton2()
        private bool CheckXButton2()
        {
            switch (_mouseKeyPosition)
            {
                case Enums.MouseKeyPositions.Down:
                    return CheckXButton2Down(_ms);

                case Enums.MouseKeyPositions.Released:
                    return CheckXButton2Released(_ms);

                case Enums.MouseKeyPositions.Pressed:
                    return CheckXButton2Pressed(_ms, _oms);
            }
            return false;
        }
        #endregion

        #region Private Method - CheckXButton2Down(MouseState ms)
        private bool CheckXButton2Down(MouseState ms)
        {
            if (ms.XButton2 == ButtonState.Pressed)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckXButton2Released(MouseState ms)
        private bool CheckXButton2Released(MouseState ms)
        {
            if (ms.XButton2 == ButtonState.Released)
                return true;
            else
                return false;
        }
        #endregion

        #region Private Method - CheckXButton2Pressed(MouseState ms, MouseState oms)
        private bool CheckXButton2Pressed(MouseState ms, MouseState oms)
        {
            if (CheckXButton2Released(ms)
                && CheckXButton2Down(oms)
                && _invoker.Rectangle.Intersects(new Rectangle(ms.X, ms.Y, 1, 1)))
                return true;
            else
                return false;
        }
        #endregion

        #endregion

        /// <summary>
        /// check for scrollwheel (this methods aren't implemented yet and cant' be used for any action)
        /// </summary>
        #region Private Methods - CheckScrollWheel

        #endregion


        #region Action Override Method - Check
        protected override void Check(MouseState ms, KeyboardState ks)
        {
            if (_enabled && _invoker.Visible && _invoker.Enabled)
            {
                _ks = Keyboard.GetState();
                _ms = Mouse.GetState();

                if (InitialMouseInsideGic)
                {
                    if (CheckMouse(_mouseKey) && KeyMod.CheckKeyModifier(_ks, _oks))
                    {
                        _target.Execute(this.Command);
                    }
                }

                _oks = _ks;
                _oms = _ms;
            }
        }
        #endregion
    }
}
